namespace System.Xml.Serialization
{
    using System;
    using System.IO;
    using System.Xml;
    using Internal;

    [Serializable]
    public abstract class XmlStreamSerializer<T> : IXmlTypeSerializer<T, MemoryStream>
    {
        [NonSerialized]
        private static readonly XmlFormatterCache _formatters = new XmlFormatterCache();
        [NonSerialized]
        private static readonly XmlSerializerCache _serializers = new XmlSerializerCache();

        private readonly Type _type = typeof(T);

        protected virtual T InternalStreamDeserialize(MemoryStream input, IXmlTypeFormatter formatter)
        {
            try
            {
                IXmlRuntimeSerializerInternal serializer = XmlRuntimeHelper.GetSerializer(typeof(T), formatter);
                if (serializer != null)
                {
                    serializer.CreateRuntimeSerializer(false);
                    using (XmlReader xmlReader = XmlReader.Create(input, serializer.ReaderSettings))
                    {
                        XmlSerializer cache = XmlStreamSerializer<T>._serializers[serializer];
                        if (cache != null)
                        {
                            return (T)cache.Deserialize(xmlReader);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                throw new XmlSerializationException();
                //PluginLog.WriteErrorSync(ex);
            }
            return default(T);
        }

        protected virtual MemoryStream InternalStreamSerialize(T obj, IXmlTypeFormatter formatter)
        {
            try
            {
                IXmlRuntimeSerializerInternal serializer = XmlRuntimeHelper.GetSerializer(typeof(T), formatter);
                if (serializer != null)
                {
                    serializer.CreateRuntimeSerializer(false);
                    using (MemoryStream output = new MemoryStream())
                    {
                        using (XmlWriter xmlWriter = XmlWriter.Create(output, serializer.WriterSettings))
                        {
                            XmlSerializer cache = XmlStreamSerializer<T>._serializers[serializer];
                            if (cache != null)
                            {
                                cache.Serialize(xmlWriter, obj);
                                return new MemoryStream(output.ToArray());
                            }
                        }
                    }
                }
                return null;
            }
            catch (Exception ex)
            {
                throw new XmlSerializationException();
                //PluginLog.WriteErrorSync(ex);
            }
        }

        protected bool OverrideRuntimeSerializer(IXmlTypeFormatter formatter, XmlSerializer value)
        {
            IXmlRuntimeSerializerInternal serializer = XmlRuntimeHelper.GetSerializer(typeof(T), formatter);
            return ((serializer != null) && XmlStreamSerializer<T>._serializers.Override(serializer, value));
        }

        T IXmlTypeSerializer<T, MemoryStream>.Deserialize(MemoryStream input)
        {
            IXmlTypeFormatter formatter = XmlStreamSerializer<T>._formatters[this._type];
            return this.InternalStreamDeserialize(input, formatter);
        }

        T IXmlTypeSerializer<T, MemoryStream>.Deserialize(MemoryStream input, IXmlRuntimeFormatter value)
        {
            IXmlTypeFormatter formatter = XmlStreamSerializer<T>._formatters[value];
            return this.InternalStreamDeserialize(input, formatter);
        }

        MemoryStream IXmlTypeSerializer<T, MemoryStream>.Serialize(T obj)
        {
            IXmlTypeFormatter formatter = XmlStreamSerializer<T>._formatters[this._type];
            return this.InternalStreamSerialize(obj, formatter);
        }

        MemoryStream IXmlTypeSerializer<T, MemoryStream>.Serialize(T obj, IXmlRuntimeFormatter value)
        {
            IXmlTypeFormatter formatter = XmlStreamSerializer<T>._formatters[value];
            return this.InternalStreamSerialize(obj, formatter);
        }

        protected IXmlTypeFormatter XmlTypeFormatter
        {
            get
            {
                return XmlStreamSerializer<T>._formatters[this._type];
            }
        }
    }
}

